﻿Imports System
Imports System.CodeDom
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.ComponentModel.Design.Serialization
Imports System.Drawing.Design
Imports System.Reflection
Imports System.Windows.Forms
Imports System.Windows.Forms.Design
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Compiler

Namespace System.Workflow.ComponentModel.Design
    Friend Class CustomActivityDesignerHelper
        ' Methods
        Private Shared Sub AddNewProperties(ByVal propCollection As List([Of] CustomProperty), ByVal customActivityType As Type, ByVal serviceProvider As IServiceProvider, ByVal existingProps As List([Of] CustomProperty))
            Dim service As IMemberCreationService = [TryCast](serviceProvider.GetService(GetType(IMemberCreationService)),IMemberCreationService)
            If (service Is Nothing) Then
                Throw New Exception(SR.GetString("General_MissingService", New Object() { GetType(IMemberCreationService).FullName }))
            End If
            Dim provider As ITypeProvider = [TryCast](serviceProvider.GetService(GetType(ITypeProvider)),ITypeProvider)
            If (provider Is Nothing) Then
                Throw New Exception(SR.GetString("General_MissingService", New Object() { GetType(ITypeProvider).FullName }))
            End If
            Dim property As CustomProperty
            For Each property In propCollection
                Dim flag As Boolean = (([property].oldPropertyName Is Nothing) OrElse ([property].oldPropertyType Is Nothing))
                If Not flag Then
                    If Not [property].IsEvent Then
                        flag = (customActivityType.GetProperty([property].oldPropertyName, provider.GetType([property].oldPropertyType)) Is Nothing)
                    Else
                        flag = (customActivityType.GetEvent([property].oldPropertyName) Is Nothing)
                    End If
                End If
                If flag Then
                    Dim attributes As AttributeInfo() = CustomActivityDesignerHelper.CreateCustomPropertyAttributeArray([property], serviceProvider)
                    If [property].IsEvent Then
                        service.CreateEvent(customActivityType.FullName, [property].Name, provider.GetType([property].Type), attributes, [property].GenerateDependencyProperty)
                    Else
                        service.CreateProperty(customActivityType.FullName, [property].Name, provider.GetType([property].Type), attributes, [property].GenerateDependencyProperty, False, False, Nothing, False)
                    End If
                    [Continue] For
                End If
                Dim oldProperty As CustomProperty = Nothing
                Dim property3 As CustomProperty
                For Each property3 In existingProps
                    If ((property3.Name = [property].oldPropertyName) AndAlso (property3.Type = [property].oldPropertyType)) Then
                        oldProperty = property3
                    End If
                Next
                If ((oldProperty Is Nothing) OrElse CustomActivityDesignerHelper.ArePropertiesDifferent([property], oldProperty)) Then
                    Dim infoArray2 As AttributeInfo() = CustomActivityDesignerHelper.CreateCustomPropertyAttributeArray([property], serviceProvider)
                    CustomActivityDesignerHelper.CreateCustomPropertyAttributeArray(oldProperty, serviceProvider)
                    Dim newEventType As Type = provider.GetType([property].Type, False)
                    Dim type As Type = provider.GetType([property].oldPropertyType, False)
                    If (Not newEventType Is Nothing) Then
                        If [property].IsEvent Then
                            service.UpdateEvent(customActivityType.FullName, [property].oldPropertyName, type, [property].Name, newEventType, infoArray2, [property].GenerateDependencyProperty, False)
                        Else
                            service.UpdateProperty(customActivityType.FullName, [property].oldPropertyName, type, [property].Name, newEventType, infoArray2, [property].GenerateDependencyProperty, False)
                        End If
                    End If
                End If
            Next
        End Sub

        Private Shared Function ArePropertiesDifferent(ByVal [property] As CustomProperty, ByVal oldProperty As CustomProperty) As Boolean
            If (((([property].Name = oldProperty.Name) AndAlso ([property].Type = oldProperty.Type)) AndAlso (([property].Browseable = oldProperty.Browseable) AndAlso ([property].Category = oldProperty.Category))) AndAlso ((([property].Description = oldProperty.Description) AndAlso ([property].DesignerSerializationVisibility = oldProperty.DesignerSerializationVisibility)) AndAlso (([property].Hidden = oldProperty.Hidden) AndAlso ([property].UITypeEditor = oldProperty.UITypeEditor)))) Then
                Return False
            End If
            Return True
        End Function

        Private Shared Function CreateCustomProperty(ByVal serviceProvider As IServiceProvider, ByVal customActivityType As Type, ByVal member As MemberInfo, ByVal propertyType As Type) As CustomProperty
            Dim property As New CustomProperty(serviceProvider) { _
                .Name = member.Name, _
                .IsEvent = TypeOf member Is EventInfo _
            }
            If (propertyType Is GetType(ActivityBind)) Then
                [property].GenerateDependencyProperty = False
                [property].Type = GetType(ActivityBind).FullName
            Else
                Dim field As FieldInfo = customActivityType.GetField((member.Name & If([property].IsEvent, "Event", "Property")), (BindingFlags.Public Or BindingFlags.Static))
                If ((Not field Is Nothing) AndAlso (field.FieldType Is GetType(DependencyProperty))) Then
                    [property].GenerateDependencyProperty = True
                Else
                    [property].GenerateDependencyProperty = False
                End If
                [property].Type = propertyType.FullName
            End If
            [property].oldPropertyName = member.Name
            [property].oldPropertyType = propertyType.FullName
            Dim customAttributes As Object() = member.GetCustomAttributes(GetType(FlagsAttribute), True)
            If ((Not customAttributes Is Nothing) AndAlso (customAttributes.Length > 0)) Then
                [property].Hidden = True
            End If
            Dim obj2 As Object
            For Each obj2 In member.GetCustomAttributes(False)
                Dim attribute As AttributeInfoAttribute = [TryCast](obj2,AttributeInfoAttribute)
                Dim info2 As AttributeInfo = If((Not attribute Is Nothing), attribute.AttributeInfo, Nothing)
                If (Not info2 Is Nothing) Then
                    Try 
                        If ((info2.AttributeType Is GetType(BrowsableAttribute)) AndAlso (info2.ArgumentValues.Count > 0)) Then
                            [property].Browseable = CBool(info2.GetArgumentValueAs(serviceProvider, 0, GetType(Boolean)))
                        ElseIf ((info2.AttributeType Is GetType(CategoryAttribute)) AndAlso (info2.ArgumentValues.Count > 0)) Then
                            [property].Category = [TryCast](info2.GetArgumentValueAs(serviceProvider, 0, GetType(String)),String)
                        ElseIf ((info2.AttributeType Is GetType(DescriptionAttribute)) AndAlso (info2.ArgumentValues.Count > 0)) Then
                            [property].Description = [TryCast](info2.GetArgumentValueAs(serviceProvider, 0, GetType(String)),String)
                        ElseIf ((info2.AttributeType Is GetType(DesignerSerializationVisibilityAttribute)) AndAlso (info2.ArgumentValues.Count > 0)) Then
                            [property].DesignerSerializationVisibility = DirectCast(info2.GetArgumentValueAs(serviceProvider, 0, GetType(DesignerSerializationVisibility)), DesignerSerializationVisibility)
                        ElseIf ((info2.AttributeType Is GetType(EditorAttribute)) AndAlso (info2.ArgumentValues.Count > 1)) Then
                            Dim type As Type = [TryCast](info2.GetArgumentValueAs(serviceProvider, 1, GetType(Type)),Type)
                            If (type Is GetType(UITypeEditor)) Then
                                Dim type2 As Type = [TryCast](info2.GetArgumentValueAs(serviceProvider, 0, GetType(Type)),Type)
                                If (Not type2 Is Nothing) Then
                                    [property].UITypeEditor = type2.FullName
                                End If
                                If String.IsNullOrEmpty([property].UITypeEditor) Then
                                    [property].UITypeEditor = [TryCast](info2.GetArgumentValueAs(serviceProvider, 0, GetType(String)),String)
                                End If
                            End If
                        End If
                    Catch obj1 As Object
                    End Try
                End If
            Next
            Return [property]
        End Function

        Private Shared Function CreateCustomPropertyAttributeArray(ByVal [property] As CustomProperty, ByVal serviceProvider As IServiceProvider) As AttributeInfo()
            If (([property] Is Nothing) OrElse [property].Hidden) Then
                Return New AttributeInfo(0  - 1) {}
            End If
            Dim list As New List([Of] AttributeInfo)
            If (Not [property].Category Is Nothing) Then
                list.Add(New AttributeInfo(GetType(CategoryAttribute), New String(0  - 1) {}, New Object() { New CodePrimitiveExpression([property].Category) }))
            End If
            If (Not [property].Description Is Nothing) Then
                list.Add(New AttributeInfo(GetType(DescriptionAttribute), New String(0  - 1) {}, New Object() { New CodePrimitiveExpression([property].Description) }))
            End If
            If Not String.IsNullOrEmpty([property].UITypeEditor) Then
                list.Add(New AttributeInfo(GetType(EditorAttribute), New String(0  - 1) {}, New Object() { New CodeTypeOfExpression([property].UITypeEditor), New CodeTypeOfExpression(GetType(UITypeEditor)) }))
            End If
            list.Add(New AttributeInfo(GetType(BrowsableAttribute), New String(0  - 1) {}, New Object() { New CodePrimitiveExpression([property].Browseable) }))
            list.Add(New AttributeInfo(GetType(DesignerSerializationVisibilityAttribute), New String(0  - 1) {}, New Object() { New CodeSnippetExpression((GetType(DesignerSerializationVisibility).Name & "." & [property].DesignerSerializationVisibility.ToString)) }))
            Return list.ToArray
        End Function

        Public Shared Function GetCustomActivityType(ByVal serviceProvider As IServiceProvider) As Type
            Dim service As IDesignerHost = [TryCast](serviceProvider.GetService(GetType(IDesignerHost)),IDesignerHost)
            If (service Is Nothing) Then
                Throw New Exception(SR.GetString("General_MissingService", New Object() { GetType(IDesignerHost).FullName }))
            End If
            Dim rootComponentClassName As String = service.RootComponentClassName
            If String.IsNullOrEmpty(rootComponentClassName) Then
                Return Nothing
            End If
            Dim provider As ITypeProvider = [TryCast](serviceProvider.GetService(GetType(ITypeProvider)),ITypeProvider)
            If (provider Is Nothing) Then
                Throw New Exception(SR.GetString("General_MissingService", New Object() { GetType(ITypeProvider).FullName }))
            End If
            Return provider.GetType(rootComponentClassName, False)
        End Function

        Friend Shared Function GetCustomProperties(ByVal serviceProvider As IServiceProvider) As List([Of] CustomProperty)
            Dim service As WorkflowDesignerLoader = [TryCast](serviceProvider.GetService(GetType(IDesignerLoaderService)),WorkflowDesignerLoader)
            If (Not service Is Nothing) Then
                service.Flush
            End If
            Dim customActivityType As Type = CustomActivityDesignerHelper.GetCustomActivityType(serviceProvider)
            If (customActivityType Is Nothing) Then
                Return Nothing
            End If
            Dim list As New List([Of] CustomProperty)
            Dim info As PropertyInfo
            For Each info In customActivityType.GetProperties((BindingFlags.Public Or (BindingFlags.Instance Or BindingFlags.DeclaredOnly)))
                If (Not info.PropertyType Is Nothing) Then
                    list.Add(CustomActivityDesignerHelper.CreateCustomProperty(serviceProvider, customActivityType, info, info.PropertyType))
                End If
            Next
            Dim info2 As EventInfo
            For Each info2 In customActivityType.GetEvents((BindingFlags.Public Or (BindingFlags.Instance Or BindingFlags.DeclaredOnly)))
                If (Not info2.EventHandlerType Is Nothing) Then
                    Dim item As CustomProperty = CustomActivityDesignerHelper.CreateCustomProperty(serviceProvider, customActivityType, info2, info2.EventHandlerType)
                    item.IsEvent = True
                    list.Add(item)
                End If
            Next
            Return list
        End Function

        Private Shared Sub RemoveDeletedProperties(ByVal propCollection As List([Of] CustomProperty), ByVal customActivityType As Type, ByVal serviceProvider As IServiceProvider)
            Dim service As IMemberCreationService = [TryCast](serviceProvider.GetService(GetType(IMemberCreationService)),IMemberCreationService)
            If (service Is Nothing) Then
                Throw New Exception(SR.GetString("General_MissingService", New Object() { GetType(IMemberCreationService).FullName }))
            End If
            Dim info As PropertyInfo
            For Each info In customActivityType.GetProperties((BindingFlags.Public Or (BindingFlags.Instance Or BindingFlags.DeclaredOnly)))
                Dim flag As Boolean = False
                Dim property As CustomProperty
                For Each property In propCollection
                    If ((info.Name = [property].oldPropertyName) AndAlso (info.PropertyType.FullName = [property].oldPropertyType)) Then
                        flag = True
                        Exit For
                    End If
                Next
                If Not flag Then
                    service.RemoveProperty(customActivityType.FullName, info.Name, info.PropertyType)
                End If
            Next
            Dim info2 As EventInfo
            For Each info2 In customActivityType.GetEvents((BindingFlags.Public Or (BindingFlags.Instance Or BindingFlags.DeclaredOnly)))
                Dim flag2 As Boolean = False
                Dim property2 As CustomProperty
                For Each property2 In propCollection
                    If ((info2.Name = property2.oldPropertyName) AndAlso (info2.EventHandlerType.FullName = property2.oldPropertyType)) Then
                        flag2 = True
                        Exit For
                    End If
                Next
                If ((Not flag2 AndAlso (Not info2.Name Is Nothing)) AndAlso (Not info2.EventHandlerType Is Nothing)) Then
                    service.RemoveEvent(customActivityType.FullName, info2.Name, info2.EventHandlerType)
                End If
            Next
        End Sub

        Public Shared Sub SetBaseTypeName(ByVal typeName As String, ByVal serviceProvider As IServiceProvider)
            If String.IsNullOrEmpty(typeName) Then
                Throw New ArgumentNullException("typeName")
            End If
            Dim host As IDesignerHost = [TryCast](serviceProvider.GetService(GetType(IDesignerHost)),IDesignerHost)
            If (host Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(IDesignerHost).FullName }))
            End If
            Dim service As IMemberCreationService = [TryCast](serviceProvider.GetService(GetType(IMemberCreationService)),IMemberCreationService)
            If (service Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(IMemberCreationService).FullName }))
            End If
            Dim fromType As Type = CustomActivityDesignerHelper.ValidateBaseType(typeName, serviceProvider)
            If (Not host.RootComponent.GetType Is fromType) Then
                If Not TypeProvider.IsAssignable(GetType(CompositeActivity), fromType) Then
                    Dim descriptor As PropertyDescriptor = TypeDescriptor.GetProperties(host.RootComponent).Item("SupportsEvents")
                    If ((Not descriptor Is Nothing) AndAlso CBool(descriptor.GetValue(host.RootComponent))) Then
                        descriptor.SetValue(host.RootComponent, False)
                    End If
                    Dim descriptor2 As PropertyDescriptor = TypeDescriptor.GetProperties(host.RootComponent).Item("SupportsExceptions")
                    If ((Not descriptor2 Is Nothing) AndAlso CBool(descriptor2.GetValue(host.RootComponent))) Then
                        descriptor2.SetValue(host.RootComponent, False)
                    End If
                End If
                Dim properties As PropertyDescriptorCollection = TypeDescriptor.GetProperties(host.RootComponent)
                If (TypeOf host.RootComponent Is CompositeActivity AndAlso (DirectCast(host.RootComponent, CompositeActivity).Activities.Count > 0)) Then
                    Dim service2 As IUIService = [TryCast](serviceProvider.GetService(GetType(IUIService)),IUIService)
                    If ((Not service2 Is Nothing) AndAlso (DialogResult.OK <> service2.ShowMessage(SR.GetString("NoChildActivities_Message"), SR.GetString("NoChildActivities_Caption"), MessageBoxButtons.OKCancel))) Then
                        Return
                    End If
                    Dim list As New List([Of] Activity)(DirectCast(host.RootComponent, CompositeActivity).Activities)
                    Dim designer As CompositeActivityDesigner = [TryCast](host.GetDesigner(host.RootComponent),CompositeActivityDesigner)
                    If (Not designer Is Nothing) Then
                        designer.RemoveActivities(list.AsReadOnly)
                    End If
                End If
                Dim descriptor3 As PropertyDescriptor
                For Each descriptor3 In properties
                    If ((Not descriptor3.Name.Equals("BaseActivityType", StringComparison.Ordinal) AndAlso Not descriptor3.Name.Equals("Name", StringComparison.Ordinal)) AndAlso descriptor3.CanResetValue(host.RootComponent)) Then
                        descriptor3.ResetValue(host.RootComponent)
                    End If
                Next
                Dim oldPropertyDescriptor As PropertyDescriptor = properties.Item("BaseActivityType")
                Dim member As PropertyDescriptor = TypeDescriptor.CreateProperty(oldPropertyDescriptor.ComponentType, oldPropertyDescriptor, New Attribute() { DesignerSerializationVisibilityAttribute.Visible })
                Dim service3 As IComponentChangeService = [TryCast](serviceProvider.GetService(GetType(IComponentChangeService)),IComponentChangeService)
                If (Not service3 Is Nothing) Then
                    service3.OnComponentChanging(host.RootComponent, member)
                End If
                DirectCast(host.RootComponent, Activity).UserData.Item(UserDataKeys.NewBaseType) = fromType
                service.UpdateBaseType(host.RootComponentClassName, fromType)
                If (Not service3 Is Nothing) Then
                    service3.OnComponentChanged(host.RootComponent, member, member.GetValue(host.RootComponent), typeName)
                End If
                Application.RaiseIdle(New EventArgs)
            End If
        End Sub

        Friend Shared Sub SetCustomProperties(ByVal customProperties As List([Of] CustomProperty), ByVal serviceProvider As IServiceProvider)
            If (customProperties Is Nothing) Then
                Throw New ArgumentNullException("customProperties")
            End If
            Dim customActivityType As Type = CustomActivityDesignerHelper.GetCustomActivityType(serviceProvider)
            If (Not customActivityType Is Nothing) Then
                Dim existingProps As List([Of] CustomProperty) = CustomActivityDesignerHelper.GetCustomProperties(serviceProvider)
                CustomActivityDesignerHelper.RemoveDeletedProperties(customProperties, customActivityType, serviceProvider)
                CustomActivityDesignerHelper.AddNewProperties(customProperties, customActivityType, serviceProvider, existingProps)
            End If
        End Sub

        Private Shared Function ValidateBaseType(ByVal typeName As String, ByVal serviceProvider As IServiceProvider) As Type
            If ((typeName Is Nothing) OrElse (typeName.Length <= 0)) Then
                Return Nothing
            End If
            Dim service As ITypeProvider = DirectCast(serviceProvider.GetService(GetType(ITypeProvider)), ITypeProvider)
            If (service Is Nothing) Then
                Throw New Exception(SR.GetString("General_MissingService", New Object() { GetType(ITypeProvider).FullName }))
            End If
            Dim fromType As Type = service.GetType(typeName)
            If (fromType Is Nothing) Then
                Throw New Exception(SR.GetString("Error_TypeNotResolved", New Object() { typeName }))
            End If
            Dim host As IDesignerHost = [TryCast](serviceProvider.GetService(GetType(IDesignerHost)),IDesignerHost)
            If (host Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(IDesignerHost).FullName }))
            End If
            Dim type As Type = service.GetType(host.RootComponentClassName)
            If ((TypeOf fromType Is DesignTimeType AndAlso (Not type Is Nothing)) AndAlso (type.Assembly Is fromType.Assembly)) Then
                Throw New InvalidOperationException(SR.GetString("Error_CantUseCurrentProjectTypeAsBase"))
            End If
            If Not TypeProvider.IsAssignable(GetType(Activity), fromType) Then
                Throw New InvalidOperationException(SR.GetString("Error_BaseTypeMustBeActivity"))
            End If
            Return fromType
        End Function

    End Class
End Namespace

